Title:

Análisis Exploratorio de Datos de Los Jugadores de La NBA

Description:

Se va a realizar un análaisis exploratorio de la base de datos all_seasons.csv correspondiente a los jugadores de la NBA

Author:

Francisco del Val Yagüe

Date:

30/10/2020

Importación de Librearias

En primer lugar, se cargan las librerias necesarias para poder realizar el correspondiente análisis de dados:

In [5]:
# Importamos pandas y numpy para poder trabajar con el dataframe
import pandas as pd
import numpy as np 

# importamos las siguientes librerias para poder hacer los graficos
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns

# uso pandas_profiling para hacer un anlisis exploratorio rapido automaticamente
from pandas_profiling import ProfileReport

Carga de Los Datos

A continuación cargamos la base de datos a estudiar:

In [6]:
# Importamos la base de datos 
NBA = pd.read_csv('../Data/01_raw/all_seasons.csv')
NBA
Out[6]:
Unnamed: 0 player_name team_abbreviation age player_height player_weight college country draft_year draft_round ... pts reb ast net_rating oreb_pct dreb_pct usg_pct ts_pct ast_pct season
0 0 Dennis Rodman CHI 36.0 198.12 99.790240 Southeastern Oklahoma State USA 1986 2 ... 5.7 16.1 3.1 16.1 0.186 0.323 0.100 0.479 0.113 1996-97
1 1 Dwayne Schintzius LAC 28.0 215.90 117.933920 Florida USA 1990 1 ... 2.3 1.5 0.3 12.3 0.078 0.151 0.175 0.430 0.048 1996-97
2 2 Earl Cureton TOR 39.0 205.74 95.254320 Detroit Mercy USA 1979 3 ... 0.8 1.0 0.4 -2.1 0.105 0.102 0.103 0.376 0.148 1996-97
3 3 Ed O'Bannon DAL 24.0 203.20 100.697424 UCLA USA 1995 1 ... 3.7 2.3 0.6 -8.7 0.060 0.149 0.167 0.399 0.077 1996-97
4 4 Ed Pinckney MIA 34.0 205.74 108.862080 Villanova USA 1985 1 ... 2.4 2.4 0.2 -11.2 0.109 0.179 0.127 0.611 0.040 1996-97
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
11140 11140 Maxi Kleber DAL 28.0 208.28 108.862080 None Germany Undrafted Undrafted ... 9.1 5.4 1.1 4.6 0.056 0.140 0.136 0.605 0.064 2019-20
11141 11141 Melvin Frazier Jr. ORL 23.0 195.58 97.522280 Tulane USA 2018 2 ... 1.2 0.3 0.1 -2.4 0.018 0.058 0.164 0.480 0.033 2019-20
11142 11142 Meyers Leonard MIA 28.0 213.36 117.933920 Illinois USA 2012 1 ... 6.1 5.1 1.1 5.6 0.029 0.217 0.120 0.640 0.076 2019-20
11143 11143 Norvel Pelle PHI 27.0 208.28 104.779752 None USA Undrafted Undrafted ... 2.1 3.0 0.4 -16.4 0.085 0.237 0.126 0.521 0.056 2019-20
11144 11144 Matt Thomas TOR 25.0 193.04 86.182480 Iowa State USA Undrafted Undrafted ... 4.5 1.4 0.5 1.0 0.017 0.104 0.149 0.663 0.089 2019-20

11145 rows × 22 columns

Diccionario de las variables:

player_name: Nombre del jugador

team_abbreviation: Nombre abreviado del equipo en el que jugo el juagodr (al final de la temporada)

age: Edad del jugador

player_height: Altura del jugador en cm

player_weight: Peso del jugador en kg

college: Nombre de la universidad que asisitio el jugador

country: Nombre del pais en el que nacio el jugador

draft_year: Año en que se seleccionó al jugador

draft_round: Ronda de draft que eligió al jugador

draf_number: El número en el que se eligió al jugador en su ronda de draft

gp: Juegos jugados durante la temporada

pts: Número medio de puntos anotados

reb: Número medio de rebotes capturados

ast: Número medio de asistencias distribuidas

net_rating:Diferencia de puntos del equipo por cada 100 posesiones mientras el jugador está en la cancha

oreb_pct: Porcentaje de rebotes ofensivos disponibles que el jugador agarró mientras estaba en el piso

dreb_pct:Porcentaje de rebotes defensivos disponibles que el jugador agarró mientras estaba en el piso

usg_pct: Porcentaje de jugadas de equipo utilizadas por el jugador mientras estaba en la cancha

ts_pct: Medida de la eficiencia de tiro del jugador que tiene en cuenta los tiros libres, tiros de 2 y 3 puntos

ast_pct: Porcentaje de puntos de campo de compañeros de equipo que el jugador ayudó mientras estaba en la cancha

season: Temporada de la NBA

Análisis Exploratorio con Pandas_Profiling

Generamos, con ayuda de ProfileReport, una breve visualizacion de los datos para realizar un primer EDA

In [7]:
profiling = ProfileReport(NBA, title = "EDA Jugadores NBA")
profiling



Out[7]:

VISUALIZACIÓN Y TRANSFORMACIÓN DE DATOS

  • Se calcula el rango del dataframe para saber con qué dimensiones tiene.
In [8]:
NBA.shape
Out[8]:
(11145, 22)

Se obtiene un resultado de 11145 filas y 22 columnas.

  • Se busca el tipo de valor de los datos del dataframe.
In [9]:
NBA.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 11145 entries, 0 to 11144
Data columns (total 22 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   Unnamed: 0         11145 non-null  int64  
 1   player_name        11145 non-null  object 
 2   team_abbreviation  11145 non-null  object 
 3   age                11145 non-null  float64
 4   player_height      11145 non-null  float64
 5   player_weight      11145 non-null  float64
 6   college            11145 non-null  object 
 7   country            11145 non-null  object 
 8   draft_year         11145 non-null  object 
 9   draft_round        11145 non-null  object 
 10  draft_number       11145 non-null  object 
 11  gp                 11145 non-null  int64  
 12  pts                11145 non-null  float64
 13  reb                11145 non-null  float64
 14  ast                11145 non-null  float64
 15  net_rating         11145 non-null  float64
 16  oreb_pct           11145 non-null  float64
 17  dreb_pct           11145 non-null  float64
 18  usg_pct            11145 non-null  float64
 19  ts_pct             11145 non-null  float64
 20  ast_pct            11145 non-null  float64
 21  season             11145 non-null  object 
dtypes: float64(12), int64(2), object(8)
memory usage: 1.9+ MB

Se obtiene 3 tipos de valores:

  • float → 12 valores
  • int → 1
  • object → 8

Se ve que los tipos de dato estan bien definidos respectivamente como float, int, object

Ahora se busca los posibles datos null aunque a priori se puede ver en la info anterior que no hay null. De todos modos lo comprobamos por si acaso.

In [10]:
NBA.isnull().sum()
Out[10]:
Unnamed: 0           0
player_name          0
team_abbreviation    0
age                  0
player_height        0
player_weight        0
college              0
country              0
draft_year           0
draft_round          0
draft_number         0
gp                   0
pts                  0
reb                  0
ast                  0
net_rating           0
oreb_pct             0
dreb_pct             0
usg_pct              0
ts_pct               0
ast_pct              0
season               0
dtype: int64

A continuación, se eliminan las columnas que no son relevantes para el estudio y se renombra el dataframe con el nombre jugadores

In [11]:
jugadores = NBA.drop(['Unnamed: 0','net_rating','oreb_pct','dreb_pct','usg_pct','ast_pct'], axis=1)
jugadores
Out[11]:
player_name team_abbreviation age player_height player_weight college country draft_year draft_round draft_number gp pts reb ast ts_pct season
0 Dennis Rodman CHI 36.0 198.12 99.790240 Southeastern Oklahoma State USA 1986 2 27 55 5.7 16.1 3.1 0.479 1996-97
1 Dwayne Schintzius LAC 28.0 215.90 117.933920 Florida USA 1990 1 24 15 2.3 1.5 0.3 0.430 1996-97
2 Earl Cureton TOR 39.0 205.74 95.254320 Detroit Mercy USA 1979 3 58 9 0.8 1.0 0.4 0.376 1996-97
3 Ed O'Bannon DAL 24.0 203.20 100.697424 UCLA USA 1995 1 9 64 3.7 2.3 0.6 0.399 1996-97
4 Ed Pinckney MIA 34.0 205.74 108.862080 Villanova USA 1985 1 10 27 2.4 2.4 0.2 0.611 1996-97
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
11140 Maxi Kleber DAL 28.0 208.28 108.862080 None Germany Undrafted Undrafted Undrafted 63 9.1 5.4 1.1 0.605 2019-20
11141 Melvin Frazier Jr. ORL 23.0 195.58 97.522280 Tulane USA 2018 2 35 15 1.2 0.3 0.1 0.480 2019-20
11142 Meyers Leonard MIA 28.0 213.36 117.933920 Illinois USA 2012 1 11 49 6.1 5.1 1.1 0.640 2019-20
11143 Norvel Pelle PHI 27.0 208.28 104.779752 None USA Undrafted Undrafted Undrafted 20 2.1 3.0 0.4 0.521 2019-20
11144 Matt Thomas TOR 25.0 193.04 86.182480 Iowa State USA Undrafted Undrafted Undrafted 31 4.5 1.4 0.5 0.663 2019-20

11145 rows × 16 columns

Ahora, renombro las columnas para trabajar con el dataframe mejor.

In [12]:
jugadores.columns = ["name",'team','age','height','weight','universuty','country','year_selection','draft_roud','draft_number','games_season','points','rebotes','assists','eficient','season']
jugadores
Out[12]:
name team age height weight universuty country year_selection draft_roud draft_number games_season points rebotes assists eficient season
0 Dennis Rodman CHI 36.0 198.12 99.790240 Southeastern Oklahoma State USA 1986 2 27 55 5.7 16.1 3.1 0.479 1996-97
1 Dwayne Schintzius LAC 28.0 215.90 117.933920 Florida USA 1990 1 24 15 2.3 1.5 0.3 0.430 1996-97
2 Earl Cureton TOR 39.0 205.74 95.254320 Detroit Mercy USA 1979 3 58 9 0.8 1.0 0.4 0.376 1996-97
3 Ed O'Bannon DAL 24.0 203.20 100.697424 UCLA USA 1995 1 9 64 3.7 2.3 0.6 0.399 1996-97
4 Ed Pinckney MIA 34.0 205.74 108.862080 Villanova USA 1985 1 10 27 2.4 2.4 0.2 0.611 1996-97
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
11140 Maxi Kleber DAL 28.0 208.28 108.862080 None Germany Undrafted Undrafted Undrafted 63 9.1 5.4 1.1 0.605 2019-20
11141 Melvin Frazier Jr. ORL 23.0 195.58 97.522280 Tulane USA 2018 2 35 15 1.2 0.3 0.1 0.480 2019-20
11142 Meyers Leonard MIA 28.0 213.36 117.933920 Illinois USA 2012 1 11 49 6.1 5.1 1.1 0.640 2019-20
11143 Norvel Pelle PHI 27.0 208.28 104.779752 None USA Undrafted Undrafted Undrafted 20 2.1 3.0 0.4 0.521 2019-20
11144 Matt Thomas TOR 25.0 193.04 86.182480 Iowa State USA Undrafted Undrafted Undrafted 31 4.5 1.4 0.5 0.663 2019-20

11145 rows × 16 columns

Se guarda la base de datos modificada

In [13]:
jugadores.to_csv("Jugadores_NBA.csv")

Análisis Estadístico de Datos

A continuación, se genera una tabla estadística donde se recoge la información estadística más relevante.

In [14]:
jugadores.describe(include='all')
Out[14]:
name team age height weight universuty country year_selection draft_roud draft_number games_season points rebotes assists eficient season
count 11145 11145 11145.000000 11145.000000 11145.000000 11145 11145 11145 11145 11145 11145.000000 11145.000000 11145.000000 11145.000000 11145.000000 11145
unique 2235 36 NaN NaN NaN 316 76 45 8 75 NaN NaN NaN NaN NaN 24
top Vince Carter CLE NaN NaN NaN None USA Undrafted 1 Undrafted NaN NaN NaN NaN NaN 2017-18
freq 22 390 NaN NaN NaN 1684 9410 1942 6513 1959 NaN NaN NaN NaN NaN 540
mean NaN NaN 27.168686 200.812818 100.637868 NaN NaN NaN NaN NaN 52.005832 8.126487 3.560036 1.801463 0.508099 NaN
std NaN NaN 4.344164 9.190973 12.576295 NaN NaN NaN NaN NaN 25.069495 5.935482 2.495394 1.789940 0.098879 NaN
min NaN NaN 18.000000 160.020000 60.327736 NaN NaN NaN NaN NaN 1.000000 0.000000 0.000000 0.000000 0.000000 NaN
25% NaN NaN 24.000000 195.580000 90.718400 NaN NaN NaN NaN NaN 32.000000 3.500000 1.800000 0.600000 0.478000 NaN
50% NaN NaN 27.000000 200.660000 99.790240 NaN NaN NaN NaN NaN 58.000000 6.600000 3.000000 1.200000 0.521000 NaN
75% NaN NaN 30.000000 208.280000 109.315672 NaN NaN NaN NaN NaN 74.000000 11.500000 4.700000 2.400000 0.557000 NaN
max NaN NaN 44.000000 231.140000 163.293120 NaN NaN NaN NaN NaN 85.000000 36.100000 16.300000 11.700000 1.500000 NaN

Histograma

Es una representacion gráfica de una variable en forma de barras que indican la frecuencia mediante una distribución de los datos

In [15]:
jugadores.hist(figsize = (10, 12), bins = 30, xlabelsize = 10, ylabelsize =10);

# figsize: tamaño de la figura
# bins: numero de rayas de las gráficas
# labelsize: tamaño del titulo de las graficas tanto las x como las y 

Correlaciones

La correlación es la proporcionalidad y la relación lineal que existe entre distintas variables. Si los valores de una variable se modifican de manera sistemática con respecto a los valores de otra, se dice que ambas variables se encuentran correlacionadas.

En primer lugar, se calculara la matriz de correlaciones y posteriormente se realizará el mapa de calor para visualizar mejor las correlaciones

  • #### Matriz de correlaciones

Se trata de una matriz simétrica donde la diagonal principal son todos 1 puesto que es la correlacion de una variable con ella misma.

In [16]:
jugadores.corr()
Out[16]:
age height weight games_season points rebotes assists eficient
age 1.000000 -0.013981 0.046904 0.046221 -0.000810 0.028319 0.083695 0.025627
height -0.013981 1.000000 0.829901 -0.005844 -0.059748 0.422547 -0.463908 0.069810
weight 0.046904 0.829901 1.000000 0.009308 -0.032130 0.436762 -0.395356 0.060416
games_season 0.046221 -0.005844 0.009308 1.000000 0.543846 0.471562 0.388840 0.389950
points -0.000810 -0.059748 -0.032130 0.543846 1.000000 0.623909 0.652098 0.382417
rebotes 0.028319 0.422547 0.436762 0.471562 0.623909 1.000000 0.224217 0.314563
assists 0.083695 -0.463908 -0.395356 0.388840 0.652098 0.224217 1.000000 0.180234
eficient 0.025627 0.069810 0.060416 0.389950 0.382417 0.314563 0.180234 1.000000
  • #### Mapa de calor (heatmap)

Es un gráfico en el que se identifica, mediante colores y de forma mas intuitiva, la visualización de la correlación entre variables.

In [17]:
# Se genera una mascara en la parte superior para que no aparezca 
mask = np.triu(np.ones_like(jugadores.corr(), dtype = bool))
            
# np.triu(): Devuelve copia de una matriz solo con los elementos debajo de la diagonal.
# np.ones_like(): Devuelve unos
    
    
# Tamaño de la figura
f, ax = plt.subplots(figsize=(20,10))

# Heatmap
sns.heatmap(jugadores.corr(), annot = True , fmt = '.2f', mask = mask, square = True, linewidths = .8, cmap = 'jet');
# annot: para que aparezcan los valores de correlaciones. por defecto es false
# fmt: cuantos decimales queremos que aparezcan '.nf' donde n es el valor que quereamos de decimales
# mask = mask: para que los datos no aparezcan dond ela mascara sea True
# square = true: para generarse los cuadrados 
# linewidht: para general el ancho entre los cuadrados 

Como se puede observar, la mayor correlacion se obtiene al relacionar las variables peso y altura. Es lógico porque cuanto mayor sea la altura de un jugador, mayor peso tendrá.

Por el contrario, practicamente no existe correlacion entre los juego por temporada y el peso, dado que jugar mas o jugar menos partidos en una temporada no viene dado por el peso del jugador.


Análisis de las variables altura y peso

  • Número de alturas
In [18]:
jugadores.height.unique()
Out[18]:
array([198.12, 215.9 , 205.74, 203.2 , 200.66, 213.36, 193.04, 182.88,
       195.58, 190.5 , 210.82, 185.42, 208.28, 177.8 , 218.44, 187.96,
       231.14, 180.34, 220.98, 228.6 , 201.  , 223.52, 160.02, 167.64,
       165.1 , 226.06, 175.26, 196.  , 183.  , 203.  ])
  • Media de altura
In [19]:
jugadores.height.mean()   # aproximadamente la altura media son 2 m
Out[19]:
200.81281830417225
  • Número de pesos
In [20]:
# numero de pesos
jugadores.weight.unique()
Out[20]:
array([ 99.79024 , 117.93392 ,  95.25432 , 100.697424, 108.86208 ,
        97.52228 ,  86.18248 , 113.398   ,  72.57472 ,  77.11064 ,
       122.46984 ,  87.996848,  80.285784, 120.20188 , 106.59412 ,
        90.7184  , 111.13004 ,  92.98636 ,  93.439952, 102.0582  ,
        83.91452 , 112.490816, 104.32616 ,  98.883056,  88.904032,
       116.119552, 127.00576 , 129.27372 ,  83.007336, 109.769264,
        81.64656 , 115.66596 ,  94.347136, 102.511792, 103.418976,
       119.748288, 137.438376,  82.553744,  87.089664,  79.3786  ,
        74.84268 ,  88.45044 , 115.212368, 132.448864,  94.800728,
       109.315672,  89.811216, 118.387512,  87.543256, 124.7378  ,
       101.604608,  96.615096,  77.564232,  73.935496, 106.140528,
        83.460928, 114.305184, 110.676448,  97.975872,  92.079176,
       136.0776  ,  85.275296,  84.821704,  86.      , 114.758776,
       112.944408, 131.54168 ,  68.945984,  85.728888, 105.233344,
       155.582056, 104.779752,  91.171992, 107.047712, 119.294696,
        81.192968,  76.203456, 122.923432,  80.739376,  63.956472,
       140.61352 , 111.583632,  73.481904,  86.636072, 102.965384,
       147.4174  , 108.408488,  96.161504,  78.471416, 101.151016,
       100.243832,  82.100152,  60.327736, 142.88148 ,  91.625584,
        70.760352, 103.872568, 125.644984,  76.657048,  92.532768,
       112.037224,  78.925008, 107.954896,  84.368112, 122.016248,
       118.841104,  90.264808,  78.017824, 128.820128, 117.026736,
       110.222856, 107.501304,  65.77084 , 105.686936,  99.336648,
        89.357624, 149.68536 ,  98.429464, 138.799152,  95.707912,
       116.573144, 131.995272,  97.068688,  61.688512,  75.296272,
       131.088088, 123.377024,  79.832192, 120.655472, 117.480328,
       130.634496, 126.552168,  68.0388  , 121.562656, 151.95332 ,
       134.263232,  74.389088, 154.22128 ,  75.749864,  93.893544,
       138.34556 , 113.851592,  73.028312, 126.098576, 121.109064,
       133.80964 , 111.      , 139.706336, 123.830616,  83.      ,
       163.29312 ,  94.      , 139.252744, 124.284208, 127.912944,
       127.459352, 141.067112])
  • Media de peso
In [21]:
jugadores.weight.mean() # existe una media de 100 kg por jugador
Out[21]:
100.63786774840734
In [22]:
# Dibujamos, con la funcion lmplot de la libreria sns, la relacion entre altura y peso de los jugadores 
# hay que incluir height para indicar el tamaño, sino no funciona
sns.lmplot(x = 'height', y = 'weight', data = jugadores, height = 10); 

Como se observa en plot anterior, existe una correlación positia por la altura cada 10 centimetros y el peso. Es decir, cada jugador que aumenta su altura en 10cm, aumenta su peso 20kg

Análisis por temporada

  • Juagadores por temporada
In [23]:
# Se utiliza value_counts() para que devuelva el numero de jugadores de cada temporada

temporada = jugadores.season.value_counts()
temporada
Out[23]:
2017-18    540
2018-19    530
2019-20    514
2014-15    492
2016-17    486
2013-14    482
2011-12    478
2015-16    476
2012-13    469
2004-05    464
2006-07    458
2005-06    458
2010-11    452
2007-08    451
2008-09    445
2009-10    442
2003-04    442
2000-01    441
1996-97    441
2001-02    440
1997-98    439
1998-99    439
1999-00    438
2002-03    428
Name: season, dtype: int64

Se obtiene la lista de temporadas ordenada por número de jugadores. Para visualizarlo mejor realizamos un plot donde se podra comparar mas facilmente.

In [24]:
plt.figure(figsize=(20,6))
sns.countplot(data=jugadores, x = "season")
plt.show()

La temporada con mayor número de jugadores es 2017-2018 con 540 jugadores. Por el contrario, la temporada 2002-2003 tiene el menor número de juagdores, 428 jugadores

Seguidamente se analiza, con ayuda de un boxplot, los puntos generados de cada temporada.

In [25]:
# Generamos el tamaño de la figura
f, ax = plt.subplots(figsize=(40, 10))

    # Dibujamos nuestro boxplot
sns.boxplot(x = 'season', y = 'points', data = jugadores, width = 0.75, palette = "Spectral");


    # Añadimos un título
plt.title('');

En el gráfico anterior se observa que no hay mucha variabilidad entre temporadas, manteniendose aproximadamente los datos. Se destaca en la temporada 2000-2001 y 2005-2006 que hay mas outlayer respecto al resto. Por lo general, en cada temporada los datos se encuentran concentrados en aquellos valores mas bajos, mientras que los valores mas altos de la puntacion tienen una dispersion mas alta.

Por ultimo, comparamos las cifras de rebotes, asistencias y puntos en función de la edad de los jugadores.

In [26]:
fig, ax = plt.subplots(nrows = 1, figsize=(25, 5)) 

ax = sns.lineplot(x='age',y='rebotes',data=jugadores, label='rebotes')
ax = sns.lineplot(x='age',y='assists',data=jugadores, label='assists')
ax = sns.lineplot(x='age',y='points',data=jugadores, label='points')
ax.set(ylabel = 'Cantidad')
ax.legend()
plt.show()

A medida que aumenta la edad hasta los 28 años las cifras de los jugadores en las tres variables tienden al alza. a partir de esta edad las cifras se ven reducidas. esto es logico porque a mas edad a apartir de los 28 años, el deporte de elite tiene una exigencia que es mas dificil de soportar para jugadores que superan esa edad

Conclusiones

Se concluye que el peso y la altura de un jugador no representa una caracteristica significativa de cara a anotar más puntos, puesto que hay axpectos del juego que permiten a los jugadores ser mas eficiente a pesar de sus condiciones fisicas. Por el contrario, la edad es un factor relevante a la hora de medir la eficacia de un jugador, puesto que al paso de la edad el jugador pierde condiciones para mantener la competitivdad.

Referencias